/*
 * Central resource for all other classes to use
 */
package org.passwordstore;

import java.io.File;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.passwordstore.util.AESCrypto;
import org.passwordstore.util.Backup;
import org.passwordstore.util.ClearMemory;
import org.passwordstore.util.ConfigParser;
import org.passwordstore.util.DataClipboard;
import org.passwordstore.util.DbDump;
import org.passwordstore.util.SQLManager;
import org.passwordstore.util.TimerAdapter;

/**
 *
 * @author thotheolh
 */
public class Resource {

    private SQLManager sql;
    private Connection dbconn;
    private Properties system;
    private Backup bk = null;
    private char[] password;
    private String username;
    private AESCrypto aescrypt;
    private DataClipboard clip;
    private static Resource instance = null;
    private ConfigParser parser;
    private Main mainInstance;
    private DbDump datdump;
    private TimerAdapter timer; // TimerAdapter. Do not use for direct manipulations of Timer.
    private Thread timerThreadInst; // Use this instance for manipulating timer thread
    private ClearMemory cm;

    protected Resource() {
        //Do not instantiate
        init();
    }

    /**
     * init() of Resource class method
     */
    public void init() {
        getSystemProperties();
        aescrypt = new AESCrypto(this);
        cm = new ClearMemory();
        setClip(new DataClipboard(this));
    }

    public static Resource getInstance() {
        if (instance == null) {
            instance = new Resource();
        }
        return instance;
    }

    /**
     * Init for database connection.
     * @param dbpath
     * @param username
     * @param password
     */
    public void initDBConn(String dbpath, String username, String password) {
        if (sql != null) {
            if (sql.isConnected()) {
                try {
                    sql.getConn().close();
                } catch (SQLException ex) {
                    Logger.getLogger(Resource.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        setSql(new SQLManager());
        getSql().connectDB(dbpath, username, password);
        bk = new Backup(this);
    }

    public void reconnectDB() {
        if (!username.isEmpty() && password.length != 0) {
            getSql().connectDB(this.getSystem().getProperty("db.connection"), username, String.valueOf(password));
        }
    }

//    /**
//     * @return the sql
//     */
    public SQLManager getSql() {
        return sql;
    }

    /**
     * @param sql the sql to set
     */
    public void setSql(SQLManager sql) {
        this.sql = sql;
    }

    /**
     * Parse 'system.properties' file to get system properties.
     */
    public void getSystemProperties() {
        parser = new ConfigParser();
        setSystem(parser.getConfig("system.properties"));
    }

    /**
     * Get system properties
     * @return system properties
     */
    public Properties getSystem() {
        return system;
    }

    /**
     * Set system properties
     * @param system properties
     */
    public void setSystem(Properties system) {
        this.system = system;
        if (parser == null) {
            parser = new ConfigParser();
        }
        parser.writeConfig("system.properties", system);
    }

    /**
     * @return the bk
     */
    public Backup getBk() {
        return bk;
    }

    /**
     * @param bk the bk to set
     */
    public void setBk(Backup bk) {
        this.bk = bk;
    }

    /**
     * @return the password
     */
    public char[] getPassword() {
        return password;
    }

    /**
     * @param password the password to set
     */
    public void setPassword(char[] password) {
        this.password = password;
    }

    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }

    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }

    /**
     * @return the aescrypt
     */
    public AESCrypto getAescrypt() {
        return aescrypt;
    }

    /**
     * @param aescrypt the aescrypt to set
     */
    public void setAescrypt(AESCrypto aescrypt) {
        this.aescrypt = aescrypt;
    }

    /**
     * @return the clip
     */
    public DataClipboard getClip() {
        return clip;
    }

    /**
     * @param clip the clip to set
     */
    public void setClip(DataClipboard clip) {
        this.clip = clip;
    }

    /**
     * @return the mainInstance
     */
    public Main getMainInstance() {
        return mainInstance;
    }

    /**
     * @param mainInstance the mainInstance to set
     */
    public void setMainInstance(Main mainInstance) {
        this.mainInstance = mainInstance;
    }

    /**
     * @return the datdump
     */
    public DbDump getDatdump() {
        return datdump;
    }

    /**
     * @param datdump the datdump to set
     */
    public void setDatdump(DbDump datdump) {
        this.datdump = datdump;
    }

    public boolean dataDumpCSV(String filename) {
        datdump = new DbDump(0);
        return datdump.doDump(filename);
    }

    public boolean dataDumpSQL(String filename) {
        datdump = new DbDump(1);
        return datdump.doDump(filename);
    }

    public void shutdown() {
        if (getSql() != null) {
            if (getSql().isConnected()) {
                getSql().disconnectDB();
                this.setPassword(new char[]{});
            }
        }
        System.exit(0);
    }

    /**
     * @return the timer
     */
    public TimerAdapter getTimer() {
        return timer;
    }

    /**
     * @param timer the timer to set
     */
    public void setTimer(TimerAdapter timer) {
        this.timer = timer;
    }

    /**
     * @return the timerThreadInst
     */
    public Thread getTimerThreadInst() {
        return timerThreadInst;
    }

    /**
     * @param timerThreadInst the timerThreadInst to set
     */
    public void setTimerThreadInst(Thread timerThreadInst) {
        this.timerThreadInst = timerThreadInst;
    }

    /**
     * Use this to start timer.
     * @param minutes
     */
    public void startTimerInstance(int minutes) {
        timer = new TimerAdapter(minutes);
        stopTimerInstance();
        setTimerThreadInst(new Thread(timer));
        getTimerThreadInst().start();
    }

    /**
     * Use this to stop timer.
     */
    public void stopTimerInstance() {
        try {
            if (getTimerThreadInst() != null) {
                if (getTimerThreadInst().isAlive()) {
                    getTimerThreadInst().interrupt();
                    setTimerThreadInst(null);
                }
            }
        } catch (Exception ex) {
            Logger.getLogger(Resource.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Process Connection Paths to identify JDBC or LocalDB urls and convert them
     * to JDBC urls.jdbc:h2:file: - jdbc h2 format. local:/DBStore/Password - localdb format
     * @param jdbcUrl
     * @return
     */
    public String processConnPath(String jdbcUrl) {
        StringBuilder strb = new StringBuilder();
        String str = "";
        String str1 = "";
        if (jdbcUrl.startsWith("local")) {
            String[] split1 = jdbcUrl.split(":");
            for (int i = 0; i < split1.length; i++) {
                if (i != 0) {
                    strb.append(split1[i].toString());
                }
            }
            str = strb.toString();
            if (str.startsWith("/")) {
                str = str.replaceFirst("/", "");
            }
            File temp = new File(str);
            str = new File("").getAbsolutePath() + "/" + temp.getPath();
            jdbcUrl = "jdbc:h2:file:" + str;
            return jdbcUrl;
        } else {
            return jdbcUrl;
        }
    }

    public void clearBytes(byte[] memspace) {
        cm.clearBytes(memspace);
    }

    public void clearLoginPassword(char[] password) {
        cm.clearLoginPassword(password);
    }
    
    public void refreshTables(){
        this.mainInstance.getMf().initTableData();
    }
}
